/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package Model;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.sql.DataSource;

/**
 *
 * @author KoBE
 */
public class ClientManagerImpl implements ClientManager{

    private static final Logger logger = Logger.getLogger(
            ClientManagerImpl.class.getName());
    private DataSource dataSource;

    public void setDataSource(DataSource ds) {
        this.dataSource = ds;
    }

     public void tryCreateTables() {
            checkDataSource();
        try {
            DBUtils.tryCreateTables(dataSource);
        } catch (SQLException ex) {
            throw new RuntimeException("Error when trying to create tables", ex);
        }
    }

    private void checkDataSource() {
        if (dataSource == null) {
            throw new IllegalStateException("DataSource is not set");
        }
    }

    public void createClient(Client client) {
        if (client == null) {
            throw new IllegalArgumentException("client");
        }

        if (client.getId() != null){
            throw new IllegalArgumentException("client is allready in");
        }

        Connection conn = null;
        try {
           conn = dataSource.getConnection();
           PreparedStatement st = conn.prepareStatement(
                    "INSERT INTO Clients (clientsName, goldMember, blackListed, registrationDate) "
                    + "VALUES (?,?,?,CURRENT_DATE)",
                    Statement.RETURN_GENERATED_KEYS);
            st.setString(1, client.getName());
            st.setString(2, client.getGoldMember());
            st.setString(3, client.getBlackListed());

            int count = st.executeUpdate();
            assert count == 1;

            Long id = getId(st.getGeneratedKeys());
            client.setId(id);

        } catch (SQLException ex) {
            logger.log(Level.SEVERE, "Error when inserting client into DB", ex);
                throw new RuntimeException("Error when inserting client into DB", ex);

        } finally {
             DBUtils.closeQuietly(conn);
        }
    }

    public void deleteClient(Client client){

        if (client == null){
        throw new IllegalArgumentException("client is null");
        }

        if (client.getId() == null){
        throw new IllegalArgumentException("client is not in the DB");
        }

        Connection conn = null;
        try {
            conn = dataSource.getConnection();
            PreparedStatement st = conn.prepareStatement("DELETE FROM Clients WHERE id=? ");
            st.setLong(1, client.getId());
            if (st.executeUpdate() == 0) {
                throw new IllegalArgumentException("client is not in the DB");
            }       
            client.setId(null);
        } catch (SQLException ex) {
            logger.log(Level.SEVERE, "Error when deleting client from DB", ex);
            throw new RuntimeException("Error when deleting client from DB", ex);

        } finally {
            DBUtils.closeQuietly(conn);
        }
    }

    public List<Client> findAllClients() {

        Connection conn = null;
        try {
            conn = dataSource.getConnection();

            PreparedStatement st = conn.prepareStatement("SELECT * FROM Clients");
            ResultSet rs = st.executeQuery();
            List<Client> clients = new ArrayList<Client>();

            while(rs.next()){
                Client client = new Client();
                client.setId(rs.getLong("id"));
                client.setName(rs.getString("clientsName"));
                client.setGoldMember(rs.getString("goldMember"));
                client.setBlackListed(rs.getString("blackListed"));
                client.setRegistrationDate(rs.getDate("registrationDate"));
                clients.add(client);
            }
            
            return clients;

        } catch (SQLException ex) {
            logger.log(Level.SEVERE, "Error when getting all clients from DB", ex);
            throw new RuntimeException("Error when getting all clients from DB", ex);
        } finally {
            DBUtils.closeQuietly(conn);
        }
    }

    public List<Client> searchClientsByString(String fulltext) {
        Connection conn = null;
        PreparedStatement st = null;
        try {
            conn = dataSource.getConnection();

            st = conn.prepareStatement("SELECT * FROM Clients WHERE "
                    +   " LOWER(name) LIKE ? ");
            st.setString(1, "%" + fulltext + "%");
            ResultSet rs = st.executeQuery();
            List<Client> found = new ArrayList<Client>();
            while (rs.next()) {
                Client result = new Client();
                result.setId(rs.getLong("id"));
                result.setName(rs.getString("name"));
                result.setGoldMember(rs.getString("goldMember"));
                result.setBlackListed(rs.getString("blackListed"));
                result.setRegistrationDate(rs.getDate("registrationDate"));
                found.add(result);
            }
            return Collections.unmodifiableList(found);
        } catch (SQLException ex) {
            logger.log(Level.SEVERE, "Error when getting all clients from DB", ex);
            throw new RuntimeException("Error when getting all clients from DB", ex);
        } finally {
            DBUtils.closeQuietly(conn);
        }
        //;
    }

    public Client findClientById(Long id) {

        if(id == null){
            throw new IllegalArgumentException("id");
        }

        Connection conn = null;
        try {
            conn = dataSource.getConnection();

            PreparedStatement st = conn.prepareStatement("SELECT * FROM Clients WHERE id=?");
            st.setLong(1, id);

            ResultSet rs = st.executeQuery();

            if (rs.next()){
                Client client = new Client();
                client.setId(rs.getLong("id"));
                client.setName(rs.getString("clientsName"));
                client.setGoldMember(rs.getString("goldMember"));
                client.setBlackListed(rs.getString("blackListed"));
                client.setRegistrationDate(rs.getDate("registrationDate"));

                assert !rs.next();
                return client;
            }else{
                return null;
            }

        } catch (SQLException ex) {
            logger.log(Level.SEVERE, "Error when getting client from DB", ex);
            throw new RuntimeException("Error when getting client from DB", ex);
        } finally {
            DBUtils.closeQuietly(conn);
        }
    }




    public void updateClient(Client client) {
        if (client == null){
            throw new IllegalArgumentException("client is null");
        }
        if (client.getId()== null ){
            throw new IllegalArgumentException("client is not in the DB");
        }     
        
        Connection conn = null;
        try {
            conn = dataSource.getConnection();

            PreparedStatement st = conn.prepareStatement("UPDATE Clients SET clientsName=?, goldMember=?, blackListed=? WHERE id=? ");
            st.setLong(4,client.getId());

            st.setString(1, client.getName());
            
            st.setString(2, client.getGoldMember());
            st.setString(3, client.getBlackListed());


            int count = st.executeUpdate();
            assert count == 1;            
            
        } catch (SQLException ex) {
            logger.log(Level.SEVERE, "Error when updating client in DB", ex);
            throw new RuntimeException("Error when updating in DB", ex);
            
        } finally {
            DBUtils.closeQuietly(conn);
        }
    }


   private static Long getId(ResultSet keys) throws SQLException {

        if (keys.getMetaData().getColumnCount() != 1) {
            throw new IllegalArgumentException("Given ResultSet contains more columns");
        }
        if (keys.next()) {
            Long result = keys.getLong(1);
            if (keys.next()) {
                throw new IllegalArgumentException("Given ResultSet contains more rows");
            }
            return result;
        } else {
            throw new IllegalArgumentException("Given ResultSet contain no rows");
        }
    }

}